package wykop.download.proxy;

import java.net.Proxy;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;

import org.apache.log4j.Logger;

import wykop.download.ProxyList;

import com.google.common.collect.Lists;

public class ProxyProvider implements Runnable, IProxyProvider {

	private static ProxyProvider instance;

	private final static Logger logger = Logger
			.getLogger("wykop.download.proxy");
	public final static List<String> defaultSitesToCheck = Arrays.asList(
			"http://www.google.pl", "http://www.wykop.pl/link/2");

	public synchronized static IProxyProvider getInstance() {
		if (instance == null) {
			final List<Proxy> proxies = ProxyList.load();
			instance = new ProxyProvider(proxies, new ProxyChecker(),
					defaultSitesToCheck);
			instance.checkAllProxies();
			new Thread(instance).start();
		}

		return instance;
	}

	private final List<Proxy> proxies;
	private final Set<Proxy> goodOnes;
	private final IProxyChecker checker;

	private final List<String> sitesToCheck;

	ProxyProvider(final List<Proxy> proxies, final IProxyChecker checker,
			final List<String> sitesToCheck) {
		this.proxies = proxies;
		this.checker = checker;
		this.sitesToCheck = sitesToCheck;
		goodOnes = new CopyOnWriteArraySet<Proxy>();
	}

	public void checkAllProxies() {
		for (final Proxy proxy : proxies) {
			boolean isOk = true;
			try {
				for (final String url : sitesToCheck) {
					if (!checker.worksWith(proxy, url)) {
						logger.info(proxy + " does not work with " + url);
						isOk = false;
						break;
					}
				}
			} catch (final Exception e) {
				isOk = false;
			}

			if (isOk) {
				logger.info(proxy + " is ok");
				goodOnes.add(proxy);
			} else {
				logger.info(proxy + " is not ok");
				goodOnes.remove(proxy);
			}
		}

		logger.info("Found " + goodOnes.size() + " working proxies");
	}

	@Override
	public Proxy getProxy() {
		final List<Proxy> all = Lists.newArrayList(goodOnes);

		if (all.size() <= 0) {
			throw new RuntimeException("No good proxy found");
		}

		final Random r = new Random();

		return all.get(Math.abs(r.nextInt()) % all.size());

	}

	public Set<Proxy> goodOnes() {
		return goodOnes;
	}

	@Override
	public void run() {

		while (true) {
			checkAllProxies();
		}

	}

}
